//
// Created by dqchen on 2022/11/2.
//

#include "lexer.h"
#include <iostream>
int convertNum(int type, int origin, int current);
Token *validNum(int type, char ch);

Lexer::Lexer(Scanner &scan): scanner(scan) {
    ch = ' ';
}

Lexer::~Lexer() {

}


Token* Lexer::fetch() {
    //循环读取字符直至结束
    for (;ch != -1;) {
        Keyword keyword;
        while (ch == ' ' || ch == '\n' || ch == '\t') {//空格、换行符、制表符继续读取下一个
            ch = scanner.scan();
        }
        if(ch == -1){//读取完毕，返回结束标记
            return new Token(END);
        }
        if (ch >= 'a' && ch <= 'z') {//识别标识符: 以小写字符开头
            return fetchId();
        } else if (ch >= '0' && ch <= '9') {//识别数字类型: 以数字开头
            Token *token = fetchNum();
            cout << " [" <<((Num*)token)->value << "]";
            return token;
        } else if(ch == '"'){//识别字符串: 以"开头
            return fetchStr();
        }else {//识别其他符号
            Token *token = fetchMark();
            cout <<" [" << token->toString() << "]";
            return token;
        }
    }
    return new Token(END);
}

Token *Lexer::fetchId() {
    Keyword keyword;
    string id = "";
    id.push_back(ch);
    while (ch != -1) {
        ch = scanner.scan();
        //如果读到数字或者下划线，则说明是标识符
        if ((ch >= '0' && ch <= '9') || '_' == ch || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
            id.push_back(ch);
        } else if(ch == '\n'){//换行符，继续读取下一个
            continue;
        }else{//否则结束
            break;
        }
    }
    Tag tag = keyword.keywords[id];//判断是否是关键字
    if(tag == STRUCT){
        return fetchStruct();
    }
    cout <<" [" << id<<"]";
    return tag ? new Token(tag) : new Id(id);
}

Token* Lexer::fetchStruct(){
    string type;
    type.push_back(ch);
    while (ch != -1) {
        ch = scanner.scan();
        if ('_' == ch || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {//如果读到下划线或者字母，则说明是标识符
            type.push_back(ch);
        } else if(ch == '\n'){//换行符，继续读取下一个
            continue;
        }else{
            break;
        }
    }
    return new Struct(type);
}

Token* Lexer::fetchNum() {
    int num = 0;
    int hex = 2; // 0, 二进制；1，八进制；2，十进制；3，十六进制；
    char old = ch;
    ch = scanner.scan();
    char next = ch;
    if (old == '0') {
        //第一个非零为十进制,通过第二个字符判断具体数值进制
        if (ch == 'b') {
            hex = 0;
        } else if (ch == 'x') {
            hex = 3;
        } else if (ch == '0' && ch <= '7') {
            hex = 1;
            num = convertNum(hex, num, ch);
        } else if (ch == ' ' || ch == ';' || ch == ')') {
            return new Num(num);
        } else if (ch == '\n') {//继续读
        }else {
            cout <<"num next token not support["<<ch<<"]"<< endl;
            return new Token(ERO);
        }
    } else {
        hex = 2;
        //如果第二个为终止符，直接返回;如果为换行符，继续往下读，否则校验值的类型并追加到num中
        if (ch == ';' || ch == ')') {
            return new Num(convertNum(hex, num, old));
        }
        if (ch != '\n') {
            //如果是其他类型且不属于数值，返回错误
            Token *t = validNum(hex, ch);
            if (t != NULL) {
                return t;
            }
        }
    }
    //明确数值类型进行初始值计算
    num = convertNum(hex, num, old);
    while (ch != -1) {
        num = convertNum(hex, num, ch);
        ch = scanner.scan();
        if (ch == ';') {
            return new Num(num);
        }
        Token *t = validNum(hex, ch);
        if (t) {
            return t;
        }
        if (ch == '\n') {
            continue;
        }
        if (ch == ' ') {
            return new Num(convertNum(hex, num, next));
        }
    }
    return nullptr;
}

Token *Lexer::fetchStr() {
    string str = "";
    while (true) {
        ch = scanner.scan();
        if(ch == '"'){
            ch = scanner.scan();
            cout <<" [" << str<<"]";
            return new Str(str);
        }
        if (ch == -1) {
            return new Token(ERO);
        }
        str.push_back(ch);
    }
}

Token *Lexer::fetchMark() {
    switch (ch) {
        case '=':
            ch = scanner.scan();
            return new Token(ASSIGN);
        case';':
            ch = scanner.scan();
            return new Token(SEM);
        case ',':
            ch = scanner.scan();
            return new Token(COMMA);
        case '+':
            ch = scanner.scan();
            return new Token(ADD);
        case '*':
            ch = scanner.scan();
            return new Token(MUL);
        case '&':
            ch = scanner.scan();
            return new Token(LEA);
        case '(':
            ch = scanner.scan();
            return new Token(LPR);
        case ')':
            ch = scanner.scan();
            return new Token(RPR);
        case '{':
            ch = scanner.scan();
            return new Token(LBE);
        case '}':
            ch = scanner.scan();
            return new Token(RBE);
        case '.':
            ch = scanner.scan();
            return new Token(POINT);
        default:
            return new Token(ERO);
    }
}

string Lexer::lineInfo() {
    return "line [" + to_string(scanner.lineNum +1) + "], col [" + to_string(scanner.colNum) +"]";
}

int convertNum(int type, int origin, int current) {
    if (current == '\n') {
        return origin;
    }
    if (type == 0) {
        return origin * 2 + current - '0';
    } else if (type == 1) {
        return origin * 8 + current - '0';

    } else if (type == 2) {
        return origin * 10 + current - '0';
    } else if (type == 3) {
        return origin * 16 + current - '0';
    }
    return origin;
}

Token *validNum(int type, char ch) {
    Token *token = nullptr;
    if (ch == '\n') {
        return token;
    }
    if (type == 0 && (ch < '0' || ch > '1')){
        return new Token(ERO);
    }
    if (type == 1 && (ch < '0' || ch > '7')) {
        return new Token(ERO);
    }
    if (type == 2 && (ch < '0' || ch > '9')) {
        return new Token(ERO);
    }
    return token;

}


